/**
 *
 */
package com.browseengine.bobo.facets.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import com.browseengine.bobo.api.BoboSegmentReader;
import com.browseengine.bobo.api.BrowseFacet;
import com.browseengine.bobo.api.BrowseSelection;
import com.browseengine.bobo.api.FacetIterator;
import com.browseengine.bobo.api.FacetSpec;
import com.browseengine.bobo.facets.FacetCountCollector;
import com.browseengine.bobo.facets.FacetCountCollectorSource;
import com.browseengine.bobo.facets.FacetHandler.FacetDataNone;
import com.browseengine.bobo.facets.RuntimeFacetHandler;
import com.browseengine.bobo.facets.data.FacetDataCache;
import com.browseengine.bobo.facets.filter.RandomAccessFilter;
import com.browseengine.bobo.sort.DocComparatorSource;
import com.browseengine.bobo.util.ListMerger;

public abstract class DynamicRangeFacetHandler extends RuntimeFacetHandler<FacetDataNone> {
  protected final String _dataFacetName;
  protected RangeFacetHandler _dataFacetHandler;

  public DynamicRangeFacetHandler(String name, String dataFacetName) {
    super(name, new HashSet<String>(Arrays.asList(new String[] { dataFacetName })));
    _dataFacetName = dataFacetName;
  }

  protected abstract String buildRangeString(String val);

  protected abstract List<String> buildAllRangeStrings();

  protected abstract String getValueFromRangeString(String rangeString);

  @Override
  public RandomAccessFilter buildRandomAccessFilter(String val, Properties props)
      throws IOException {
    return _dataFacetHandler.buildRandomAccessFilter(buildRangeString(val), props);
  }

  @Override
  public RandomAccessFilter buildRandomAccessAndFilter(String[] vals, Properties prop)
      throws IOException {
    List<String> valList = new ArrayList<String>(vals.length);
    for (String val : vals) {
      valList.add(buildRangeString(val));
    }

    return _dataFacetHandler.buildRandomAccessAndFilter(
      valList.toArray(new String[valList.size()]), prop);
  }

  @Override
  public RandomAccessFilter buildRandomAccessOrFilter(String[] vals, Properties prop, boolean isNot)
      throws IOException {
    List<String> valList = new ArrayList<String>(vals.length);
    for (String val : vals) {
      valList.add(buildRangeString(val));
    }
    return _dataFacetHandler.buildRandomAccessOrFilter(valList.toArray(new String[valList.size()]),
      prop, isNot);
  }

  @Override
  public FacetCountCollectorSource getFacetCountCollectorSource(final BrowseSelection sel,
      final FacetSpec fspec) {
    final List<String> list = buildAllRangeStrings();
    return new FacetCountCollectorSource() {
      @Override
      public FacetCountCollector getFacetCountCollector(BoboSegmentReader reader, int docBase) {
        FacetDataCache<?> dataCache = _dataFacetHandler.getFacetData(reader);
        return new DynamicRangeFacetCountCollector(getName(), dataCache, docBase, fspec, list);
      }
    };
  }

  @Override
  public String[] getFieldValues(BoboSegmentReader reader, int docid) {
    return _dataFacetHandler.getFieldValues(reader, docid);
  }

  @Override
  public Object[] getRawFieldValues(BoboSegmentReader reader, int docid) {
    return _dataFacetHandler.getRawFieldValues(reader, docid);
  }

  @Override
  public DocComparatorSource getDocComparatorSource() {
    return _dataFacetHandler.getDocComparatorSource();
  }

  @Override
  public FacetDataNone load(BoboSegmentReader reader) throws IOException {
    _dataFacetHandler = (RangeFacetHandler) getDependedFacetHandler(_dataFacetName);
    return FacetDataNone.instance;
  }

  private class DynamicRangeFacetCountCollector extends RangeFacetCountCollector {
    DynamicRangeFacetCountCollector(String name, FacetDataCache<?> dataCache, int docBase,
        FacetSpec fspec, List<String> predefinedList) {
      super(name, dataCache, docBase, fspec, predefinedList);
    }

    @Override
    public BrowseFacet getFacet(String value) {
      String rangeString = buildRangeString(value);
      BrowseFacet facet = super.getFacet(rangeString);
      if (facet != null) {
        return new BrowseFacet(value, facet.getFacetValueHitCount());
      } else {
        return null;
      }
    }

    @Override
    public int getFacetHitsCount(Object value) {
      String rangeString = buildRangeString((String) value);
      return super.getFacetHitsCount(rangeString);
    }

    @Override
    public List<BrowseFacet> getFacets() {
      List<BrowseFacet> list = super.getFacets();
      ArrayList<BrowseFacet> retList = new ArrayList<BrowseFacet>(list.size());
      Iterator<BrowseFacet> iter = list.iterator();
      while (iter.hasNext()) {
        BrowseFacet facet = iter.next();
        String val = facet.getValue();
        String rangeString = getValueFromRangeString(val);
        if (rangeString != null) {
          BrowseFacet convertedFacet = new BrowseFacet(rangeString, facet.getFacetValueHitCount());
          retList.add(convertedFacet);
        }
      }
      return retList;
    }

    @Override
    public FacetIterator iterator() {
      FacetIterator iter = super.iterator();

      List<BrowseFacet> facets = new ArrayList<BrowseFacet>();
      while (iter.hasNext()) {
        Comparable<?> facet = iter.next();
        int count = iter.count;
        facets.add(new BrowseFacet(getValueFromRangeString(String.valueOf(facet)), count));
      }
      Collections.sort(facets, ListMerger.FACET_VAL_COMPARATOR);
      return new PathFacetIterator(facets);
    }
  }
}
